/*
 * =====================================================================================
 *
 *       Filename:  redis_cluster.h
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  03/15/2018 04:18:11 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */
#ifndef REDIS_CLUSTER_H
#define REDIS_CLUSTER_H

#include <string>
#include <map>
#include <vector>

#include "redis_conn.h"

using std::string;
using std::map;
using std::vector;

struct SlotRange
{
    SlotRange(unsigned int min, unsigned int max):
        m_max(max),m_min(min)
    {
    }
    
    bool operator <(const SlotRange& other) const
    {
        return m_min< other.m_min;
    }

    unsigned int  m_min;
    unsigned int  m_max;
};

struct ClusterNode
{
    ClusterNode(const string& ip,unsigned int port):
        m_ip(ip),m_port(port)
    {
    }
    
    ClusterNode(const string& ip,unsigned int port,const string& nodeid):
        m_ip(ip),m_port(port),m_id(nodeid)
    {
    }

    bool operator <(const ClusterNode& other) const
    {
        if (m_ip != other.m_ip)
            return m_ip < other.m_ip;
        return m_port < other.m_port;
    }
    
    unsigned int    m_port;
    string          m_ip;
    string          m_id;
};

// only for access,not for slot deleting or adding 
// process or thread safety not guaranteed
class RedisCluster
{
public:
    static RedisCluster* instance();
    static void release();

    bool loadSlots(const vector<ClusterNode>& nodes,const struct timeval& tmout);
    RedisConn* getConn(const string& key);
    RedisConn* getConn(const ClusterNode& node);
    RedisConn* getConn(const string& ip,unsigned int port);

public:
    // for test
    map<SlotRange,vector<ClusterNode> >* getNodes()
    {
        return &m_nodes;
    }
    map<ClusterNode,RedisConn*>* getConns()
    {
        return &m_conns;
    }
	
	void clear();
private:
    RedisCluster()
    {}
	~RedisCluster();

    RedisCluster(const RedisCluster& other);
    RedisCluster& operator=(const RedisCluster& other);
	// slot change
    friend RedisConn* RedisConn::getMovedConn(const string& errmsg);
    bool reloadSlots();
private:
    static RedisCluster                     *m_instance;

    friend bool RedisConn::loadClusterSlots(const struct timeval& tmout);
    map<SlotRange,vector<ClusterNode> >     m_nodes;
    map<ClusterNode,RedisConn*>             m_conns;
};




#endif









